package com.dayu.finecomm.device;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.dayu.finecomm.decoder.HdTcpDecoder;
import com.dayu.finecomm.handler.cmd.CMDSendHandler;
import com.dayu.finecomm.handler.tpacket.TPacketCollectHandler;
import com.dayu.finecomm.handler.tpacket.TPacketCommitHandler;
import com.dayu.finecomm.handler.tpacket.TPacketOPCUAHandler;
import com.dayu.finecomm.handler.tpacket.TPacketPushHandler;
import com.dayu.finecomm.pojo.DeviceConfig;
import com.dayu.finecomm.pojo.DevicePusher;
import com.dayu.finecomm.protocol.Protocols;
import com.dayu.finecomm.protocol.codec.Drive;
import com.dayu.finecomm.protocol.codec.ProtocolDecoder;
import com.dayu.finecomm.protocol.log.ProtocolLogger;
import com.dayu.finecomm.protocol.pojo.TPacket;
import com.dayu.finecomm.source.CollectSource;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;

/**
 * @ClassName: TcpDevice
 * @Description:TCP设备
 * @author: 戴卫国
 * @date: 2018年2月23日 下午3:54:22
 * 
 * @Copyright: 2018 dayu Inc. All rights reserved.
 */
@Drive(TcpDevice.DRIVE)
public class TcpDevice extends ChannelInitializer<NioSocketChannel> implements Device {

	static final String DRIVE = "tcp";

	private Map<String, ChannelHandlerContext> listeners;

	final Set<String> protocols;
	private Set<InetSocketAddress> distributors;
	private Collection<DevicePusher> pushers;

	@Override
	public Collection<DevicePusher> getPushers() {
		return pushers;
	}

	@Override
	public void setPushers(Collection<DevicePusher> pushers) {
		this.pushers = pushers;
	}

	/**
	 * @Fields config : 网关
	 */
	final DeviceConfig config;
	/**
	 * @Fields prefix : 前缀
	 */
	final String prefix;

	/**
	 * @Fields listenType : 监听类型
	 */
	private String listenType;

	private List<ProtocolDecoder<TPacket>> protocolDecoders;
	private CollectSource stations;

	public TcpDevice(final CollectSource stations, final Set<String> protocols, final DeviceConfig config) {

		this.protocols = protocols;
		this.prefix = config.prefix;
		this.stations = stations;
		this.config = config;

		protocolDecoders = Protocols.protocols(this.protocols);
	}

	@Override
	protected void initChannel(NioSocketChannel ctx) throws Exception {

		// 获取过程
		ChannelPipeline pipeline = ctx.pipeline();

		// 报文解析
		pipeline.addLast(new HdTcpDecoder(this.prefix, protocolDecoders));
		// 命令下发
		pipeline.addLast(new TPacketCommitHandler(this));
		// 报文组装
		pipeline.addLast(new TPacketCollectHandler(stations, false, config.name));
		// 报文分发
		pipeline.addLast(new TPacketPushHandler(this, config));

		if (config.opcUaEnabled) {
			pipeline.addLast(new TPacketOPCUAHandler(config.opcUaEndPoint));
		}
		//
		// pipeline.addLast(new CMDStoreHandler(stations));
		//
		pipeline.addLast(new CMDSendHandler(stations));
		// 日志打印
		pipeline.addLast(new ProtocolLogger());

		if (this.config.idle > 0) {

			// Max idle time 600s
			pipeline.addFirst(new ReadTimeoutHandler(this.config.idle));
		}
	}

	@Override
	public Map<String, ChannelHandlerContext> getListeners() {
		return listeners;
	}

	@Override
	public void setListeners(Map<String, ChannelHandlerContext> lITENERS) {
		listeners = lITENERS;
	}

	@Override
	public Set<InetSocketAddress> getDistributors() {
		return distributors;
	}

	@Override
	public void setDistributors(Set<InetSocketAddress> distributors) {
		this.distributors = distributors;
	}

	@Override
	public String getListenType() {
		return listenType;
	}

	@Override
	public void setListenType(String listenType) {
		this.listenType = listenType;
	}

}